/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package create_view_modify;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfWriter;
import cse308.GUIUtilityClass;
import cse308.entities.Courseinfo;
import cse308.entities.Courseoffering;
import cse308.entities.Courseoutcome;
import cse308.entities.Courseoutcomedirectassessment;
import cse308.entities.Courseoutcomesurveyresults;
import cse308.entities.Degreeprogram;
import cse308.entities.Peo;
import cse308.entities.Peoattainment;
import cse308.entities.Studentoutcome;
import cse308.entities.Targetsurveyassessment;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ValueExpression;
import javax.faces.application.FacesMessage;
import javax.faces.component.html.HtmlColumn;
import javax.faces.component.html.HtmlDataTable;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.component.html.HtmlPanelGroup;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;


/**
 *
 * @author Aaron
 */
public class TabulateInfoBean implements Serializable {

    /**
     * Creates a new instance of TabulateInfoBean
     */
    private HtmlPanelGroup dataTableGroup;
    private String degreeProgram;
    private int startYear;
    private int endYear;
    private boolean buttonClicked;
    private List<String> currentColumnHeaders;
    private String whichTabulate;
    private List<List<String>> tabulateList;
    private boolean alumniSurvey;
    private boolean employerSurvey;
 private final static Logger LOG = Logger.getLogger(GUIUtilityClass.class.getName());
    public TabulateInfoBean() {
        this.dataTableGroup = new HtmlPanelGroup();
        this.currentColumnHeaders = new ArrayList();
        this.tabulateList = new ArrayList();
        this.alumniSurvey = false;
        this.employerSurvey = false;
    }

    public String getDegreeProgram() {
        return degreeProgram;
    }

    public void setDegreeProgram(String degreeProgram) {
        this.degreeProgram = degreeProgram;
    }

    public int getStartYear() {
        return startYear;
    }

    public void setStartYear(int startYear) {
        this.startYear = startYear;
    }

    public int getEndYear() {
        return endYear;
    }

    public void setEndYear(int endYear) {
        this.endYear = endYear;
    }

    public String beginTabulating() {
        this.currentColumnHeaders = new ArrayList();
        this.currentColumnHeaders.add("");
        this.tabulateList = new ArrayList();
        HtmlDataTable dataTable = new HtmlDataTable();
        FacesContext fc = FacesContext.getCurrentInstance();
        Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
        whichTabulate = params.get("whichTabulate");
        boolean success = true;
        switch (whichTabulate) {
            case "TDSOA":
                success = this.TSASOA(false);
                break;
            case "TDSOAC":
                success = this.TDSOAC();
                break;
            case "TPA":
                success = this.TPA();
                break;
            case "TSASOA":
                success = TSASOA(true);
                break;
            case "TSOAC":
                success = this.TSOAC();
                break;
            case "TDSOEC":
                success = this.TDSOEC();
                break;
        }
        if (!success) {
            FacesMessage message = new FacesMessage();
            message.setDetail("Invalid Degree Program");
            FacesContext.getCurrentInstance().addMessage("form", message);
            return "";
        }
        ValueExpression ve = fc.getApplication().getExpressionFactory().createValueExpression(fc.getELContext(),
                "#{tabulateInfoBean.tabulateList}", List.class);
        dataTable.setValueExpression("value", ve);
        dataTable.setVar("tabulate");
        for (int i = 0; i < this.currentColumnHeaders.size(); i++) {
            String currentHeader = this.currentColumnHeaders.get(i);
            HtmlColumn currentColumn = new HtmlColumn();
            dataTable.getChildren().add(currentColumn);
            HtmlOutputText header = new HtmlOutputText();
            header.setValue(currentHeader);
            currentColumn.setHeader(header);
            HtmlOutputText output = new HtmlOutputText();
            ValueExpression ve2 = fc.getApplication().getExpressionFactory().createValueExpression(fc.getELContext(),
                    "#{tabulate[" + i + "]}", String.class);
            output.setValueExpression("value", ve2);
            currentColumn.getChildren().add(output);
        }
        this.dataTableGroup = new HtmlPanelGroup();
        dataTableGroup.getChildren().add(dataTable);
       // this.pruneList();
        return "TabulatePage";
    }

    public boolean TPA() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("CSE_308_ABETPU");
        EntityManager em = emf.createEntityManager();
        Degreeprogram dp = em.find(Degreeprogram.class, this.degreeProgram);
        if (dp == null) {
            return false;
        }
        Collection<Peo> peosForDegreeProgram = dp.getPeoCollection();
       
        for(Peo p : peosForDegreeProgram){
            currentColumnHeaders.add(p.getIdentifier());
        }
        for (int i = this.startYear; i <= this.endYear; i++) {
            ArrayList<String> currentPeoAttainments = new ArrayList();
            currentPeoAttainments.add(String.valueOf(i));
            for (Peo currentPeo : peosForDegreeProgram) {
                ArrayList<Peoattainment> associatedAttainments = new ArrayList(currentPeo.getPeoattainmentCollection());
                currentPeoAttainments.add(this.calculateTPACell(associatedAttainments, i, currentPeo));
            }
            this.tabulateList.add(currentPeoAttainments);
        }
        return true;
    }

    public String calculateTPACell(ArrayList<Peoattainment> associatedAttainments, int i, Peo currentPeo) {
        int average = 0;
        int num = 0;
        if (this.alumniSurvey) {
            List<Peoattainment> foundAttainment = this.getPeoattainmentForYear(i, true, associatedAttainments,
                    currentPeo);
            if (foundAttainment != null) {
                for (Peoattainment resultAttainment : foundAttainment) {
                    average += Double.valueOf(resultAttainment.getAttainmentlevel());
                    num++;
                }
            }
        }
        if (this.employerSurvey) {
            List<Peoattainment> foundAttainment = this.getPeoattainmentForYear(i, false, associatedAttainments,
                    currentPeo);
            if (foundAttainment != null) {
                for (Peoattainment resultAttainment : foundAttainment) {
                    average += Double.valueOf(resultAttainment.getAttainmentlevel());
                    num++;
                }
            }
        }
        if (!this.alumniSurvey && !this.employerSurvey) {
            return "";
        }
        return (num != 0) ? String.valueOf(average / num) : "";
    }

    public List<Peoattainment> getPeoattainmentForYear(int year, boolean isAlumni,
            ArrayList<Peoattainment> associatedAttainments, Peo currentPeo) {
        List<Peoattainment> listOfAttainments = new ArrayList();
        if (isAlumni) {
            for (Peoattainment attainment : associatedAttainments) {
                if (attainment.getSurveyidentifier().getGroupBelong().equalsIgnoreCase("alumni")
                        && attainment.getYea().equals(String.valueOf(year))
                        && attainment.getPeoIdentifier().equals(currentPeo)) {
                    listOfAttainments.add(attainment);
                }
            }
        } else {
            for (Peoattainment attainment : associatedAttainments) {
                if (attainment.getSurveyidentifier().getGroupBelong().equalsIgnoreCase("employer")
                        && attainment.getYea().equals(String.valueOf(year))
                        && attainment.getPeoIdentifier().equals(currentPeo)) {
                    listOfAttainments.add(attainment);
                }
            }
        }
        return listOfAttainments;
    }

    public boolean TDSOA() {
        return true;
    }

    public boolean TDSOAC() {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("CSE_308_ABETPU");
        EntityManager em = emf.createEntityManager();
        Degreeprogram degreeProgramResult = em.find(Degreeprogram.class, this.degreeProgram);
        if (degreeProgramResult == null) {
            return false;
        }
        Collection<Studentoutcome> studentOutcomes = degreeProgramResult.getStudentoutcomeCollection();
        Collection<Studentoutcome> validStudentOutcomes = new ArrayList();
        for (Studentoutcome so : studentOutcomes) {
            if (so.getYea() != null) {
                int soStartYear = so.getYea();
                int soEndYear = (so.getEndyear() != null) ? so.getEndyear() : Calendar.getInstance().get(Calendar.YEAR);
                if (soStartYear <= this.endYear && soEndYear >= this.startYear) {
                    this.currentColumnHeaders.add(so.getIdentifier());
                    validStudentOutcomes.add(so);
                }
            }
        }
        Collection<Courseinfo> courses = degreeProgramResult.getCourseinfoCollection();
        for (Courseinfo course : courses) {
            Collection<Courseoffering> correspondingOfferings = course.getCourseofferingCollection();

            ArrayList<String> currentRow = new ArrayList();
            currentRow.add(course.getIdentifier());
            for (Studentoutcome so : validStudentOutcomes) {
                String average = calculateCell(so, course, correspondingOfferings);
                currentRow.add(average);
            }
            this.tabulateList.add(currentRow);
        }
        List<String> totalAverages = new ArrayList();
        totalAverages.add("Averages");
        for (int i = 1; i < this.currentColumnHeaders.size(); i++) {
            double average = 0.0;
            int numCell = 0;
            for (int j = 0; j < this.tabulateList.size(); j++) {
                if (!this.tabulateList.get(j).get(i).equals("")) {
                    if(this.tabulateList.get(j).get(i).equals("")) continue;
                    average += Double.parseDouble(this.tabulateList.get(j).get(i));
                    numCell++;
                }
            }
            DecimalFormat df = new DecimalFormat("#.00");
            average = (numCell != 0) ? average / numCell : 0;
            String averageString = df.format(average);
            totalAverages.add(averageString);
        }
        this.tabulateList.add(totalAverages);
        return true;
    }

    public String calculateCell(Studentoutcome so, Courseinfo course,
            Collection<Courseoffering> correspondingOfferings) {
        Double average = 0.0;
        Integer numCell = 0;
        Collection<Courseoutcome> soAssociated = so.getCourseoutcomeCollection();
        Collection<Courseoutcome> courseAssociated = course.getCourseoutcomeCollection();
        Collection<Courseoutcome> commonElements = this.getCommonElements(soAssociated, courseAssociated);
        for (Courseoffering courseOfferings : correspondingOfferings) {
            average += this.calculateFromCODA(courseOfferings, commonElements);
            numCell++;
        }

        DecimalFormat df = new DecimalFormat("#.00");
        Double av = (numCell!=0) ? average/numCell : 0;
        String avString = df.format(av);
        return avString;
    }

    public Double calculateFromCODA(Courseoffering courseOfferings, Collection<Courseoutcome> commonElements) {
        Double courseOfferingAverage = 0.0;
        Integer num = 0;
        Collection<Courseoutcomedirectassessment> codal = courseOfferings.getCourseoutcomedirectassessmentCollection();
        for (Courseoutcomedirectassessment coda : codal) {
            if (commonElements.contains(coda.getCourseoutcome())) {
                courseOfferingAverage += coda.getAttainmentLevel();
                num++;
            }
        }
        courseOfferingAverage = (num!=0) ? courseOfferingAverage/num : 0;
        return courseOfferingAverage;
    }

    public Double calculateFromCOSA(Courseoffering courseOfferings, Collection<Courseoutcome> commonElements) {
        Double courseOfferingAverage = 0.0;
        Integer num = 0;
        Collection<Courseoutcomesurveyresults> cosal = courseOfferings.getCourseoutcomesurveyresultsCollection();
        for (Courseoutcomesurveyresults cosa : cosal) {
            if (commonElements.contains(cosa.getCourseoutcomeIdentifier())) {
                courseOfferingAverage += cosa.getAverageRatingAttainment();
                num++;
            }
        }
        if (num != 0) {
            courseOfferingAverage /= num;
        }
        return courseOfferingAverage;
    }

    public boolean TSASOA(boolean isTSASOA) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("CSE_308_ABETPU");
        EntityManager em = emf.createEntityManager();
        
        Degreeprogram degreeProgramResult = em.find(Degreeprogram.class, this.degreeProgram);
        if (degreeProgramResult == null) {
            return false;
        }
        Collection<Studentoutcome> studentOutcomes = degreeProgramResult.getStudentoutcomeCollection();
        Collection<Studentoutcome> validStudentOutcomes = new ArrayList();
        for (Studentoutcome so : studentOutcomes) {
            if (so.getYea() != null) {
                int soStartYear = so.getYea();
                int soEndYear = (so.getEndyear() != null) ? so.getEndyear() : Calendar.getInstance().get(Calendar.YEAR);
                if (soStartYear <= this.endYear && soEndYear >= this.startYear) {
                    this.currentColumnHeaders.add(so.getIdentifier());
                    validStudentOutcomes.add(so);
                }
            }
        }
        List<String> targetList = new ArrayList();
        targetList.add("Target");
        for (Studentoutcome so : validStudentOutcomes) {
            Collection<Targetsurveyassessment> tsac = so.getTargetsurveyassessmentCollection();
            String latestTarget = "";
            for (Targetsurveyassessment tsa : tsac) {
                String semester = tsa.getTargetsurveyassessmentPK().getSemester();
                StringTokenizer st = new StringTokenizer(semester);
                st.nextToken();
                int currentYear = Integer.parseInt(st.nextToken());
                if (currentYear <= this.endYear && tsa.getAttainmentlevel() != null) {
                    latestTarget = String.valueOf(tsa.getAttainmentlevel());
                }
            }
            targetList.add(latestTarget);
        }
        this.tabulateList.add(targetList);
        for (int i = this.startYear; i <= this.endYear; i++) {
            ArrayList<String> currentRow = new ArrayList();
            currentRow.add(String.valueOf(i));
            for (Studentoutcome so : validStudentOutcomes) {
                String average = calculateTSASOACell(so, degreeProgramResult.getCourseinfoCollection(), i,
                        isTSASOA);
                currentRow.add(average);
            }
            this.tabulateList.add(currentRow);
        }
        return true;
    }

    public String calculateTSASOACell(Studentoutcome so, Collection<Courseinfo> courses, int currentYear,
            boolean isTSASOA) {
        Double average = 0.0;
        Integer numCell = 0;
        for (Courseinfo course : courses) {
            Double courseAverage = 0.0;
            Integer numCellCourse = 0;
            Collection<Courseoutcome> soAssociated = so.getCourseoutcomeCollection();
            Collection<Courseoutcome> courseAssociated = course.getCourseoutcomeCollection();
            Collection<Courseoutcome> commonElements = this.getCommonElements(soAssociated, courseAssociated);
            if(commonElements.isEmpty()) continue;
            Collection<Courseoffering> correspondingOfferings = validCourseOfferings(course, currentYear);
            for (Courseoffering courseOfferings : correspondingOfferings) {
                boolean skip=false;
                if(isTSASOA){
                    if(courseOfferings.getCourseoutcomesurveyresultsCollection().isEmpty()){
                        skip=true;
                    }
                }
                else{
                    if(courseOfferings.getCourseoutcomedirectassessmentCollection().isEmpty()){
                        skip=true;
                    }
                }
                if(skip) continue;
                if (isTSASOA) {
                    courseAverage += this.calculateFromCOSA(courseOfferings, commonElements);
                } else {
                    courseAverage += this.calculateFromCODA(courseOfferings, commonElements);
                    
                }
                numCellCourse++;
            }
            if (numCellCourse != 0) {
                courseAverage /= numCellCourse;
                average += courseAverage;
                numCell++;
            }
        }
        Double av = (numCell!=0) ? average/numCell : 0; 
        DecimalFormat df = new DecimalFormat("#.00");
        String avString = df.format(av);
        return avString;
    }

    public Collection<Courseoffering> validCourseOfferings(Courseinfo course, int currentYear) {
        Collection<Courseoffering> validCourseOffering = new ArrayList();
        Collection<Courseoffering> allCourseOffering = course.getCourseofferingCollection();
        for (Courseoffering co : allCourseOffering) {
            String semester = co.getCourseofferingPK().getSemester();
            StringTokenizer st = new StringTokenizer(semester);
            st.nextToken();
            int year = Integer.valueOf(st.nextToken());
            if (year == currentYear) {
                validCourseOffering.add(co);
            }
        }
        return validCourseOffering;
    }

    public boolean TSOAC() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("CSE_308_ABETPU");
        EntityManager em = emf.createEntityManager();
        Degreeprogram degreeProgramResult = em.find(Degreeprogram.class, this.degreeProgram);
        if (degreeProgramResult == null) {
            return false;
        }
        Collection<Studentoutcome> studentoutcomelist = degreeProgramResult.getStudentoutcomeCollection();
        Collection<Courseinfo> courselist = degreeProgramResult.getCourseinfoCollection();
        for(Courseinfo ci : courselist){
            List<String> tabulatedlist = new ArrayList();
            tabulatedlist.add(ci.getIdentifier());
            for(Studentoutcome sc : studentoutcomelist){
                tabulatedlist.add("");
                for(Courseoutcome co : ci.getCourseoutcomeCollection()){
                    if(co.getStudentoutcome().equals(sc)){
                        if(co.getAssessed()==true){
                            tabulatedlist.set(tabulatedlist.size()-1, "x");
                            break;
                        }
                    }
                }
                tabulatedlist.add("");
            }
            this.tabulateList.add(tabulatedlist);
        }
        this.currentColumnHeaders.add("");
        for(Studentoutcome sc : studentoutcomelist){
            this.currentColumnHeaders.add(sc.getIdentifier());
        }
        return true;
    }

    public boolean TDSOEC() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("CSE_308_ABETPU");
        EntityManager em = emf.createEntityManager();
        Degreeprogram degreeProgramResult = em.find(Degreeprogram.class, this.degreeProgram);
        if (degreeProgramResult == null) {
            return false;
        }
        Collection<Studentoutcome> studentoutcomelist = degreeProgramResult.getStudentoutcomeCollection();
        Collection<Courseinfo> courselist = degreeProgramResult.getCourseinfoCollection();
        for(Courseinfo ci : courselist){
            List<String> tabulatedlist = new ArrayList();
            tabulatedlist.add(ci.getIdentifier());
            for(Studentoutcome sc : studentoutcomelist){
                tabulatedlist.add("");
                for(Courseoutcome co : ci.getCourseoutcomeCollection()){
                    if(co.getStudentoutcome().equals(sc)){
                        tabulatedlist.set(tabulatedlist.size()-1, "x");
                        break;
                    }
                }
                tabulatedlist.add("");
            }
            this.tabulateList.add(tabulatedlist);
        }
        this.currentColumnHeaders.add("");
        for(Studentoutcome sc : studentoutcomelist){
            this.currentColumnHeaders.add(sc.getIdentifier());
        }
        return true;
    }

    public boolean isButtonClicked() {
        return buttonClicked;
    }

    public void setButtonClicked(boolean buttonClicked) {
        this.buttonClicked = buttonClicked;
    }

    public HtmlPanelGroup getDataTableGroup() {
        return dataTableGroup;
    }

    public void setDataTableGroup(HtmlPanelGroup dataTableGroup) {
        this.dataTableGroup = dataTableGroup;
    }

    public List<String> getCurrentColumnHeaders() {
        return currentColumnHeaders;
    }

    public void setCurrentColumnHeaders(List<String> currentColumnHeaders) {
        this.currentColumnHeaders = currentColumnHeaders;
    }

    public String getWhichTabulate() {
        return whichTabulate;
    }

    public void setWhichTabulate(String whichTabulate) {
        this.whichTabulate = whichTabulate;
    }

    public List<List<String>> getTabulateList() {
        return tabulateList;
    }

    public void setTabulateList(List<List<String>> tabulateList) {
        this.tabulateList = tabulateList;
    }

    public Collection<Courseoutcome> getCommonElements(Collection<Courseoutcome> soAssociated, Collection<Courseoutcome> courseAssociated) {
        Collection<Courseoutcome> associatedElements = new ArrayList();
        for (Courseoutcome co : soAssociated) {
            for (Courseoutcome co2 : courseAssociated) {
                if (co.equals(co2)) {
                    associatedElements.add(co);
                    break;
                }
            }
        }
        return associatedElements;
    }

    public void pruneList() {
        List<List<String>> newTabulateList = new ArrayList();

        for (int i = 0; i < this.tabulateList.size(); i++) {
            boolean add = false;
            for (int j = 1; j < this.tabulateList.get(i).size(); j++) {
                if (!this.tabulateList.get(i).get(j).equals("")) {
                    add = true;
                }
            }
            if (add) {
                newTabulateList.add(this.tabulateList.get(i));
            }
        }
        this.tabulateList = newTabulateList;
    }

    public void createPDF() {
        Document document = new Document();
        try {
            
            PdfWriter.getInstance(document, new FileOutputStream("C://tmp/" + whichTabulate + ".pdf"));
            document.open();
            String headers = "\t";
            for(int i=1; i<this.currentColumnHeaders.size(); i++){
                headers+= " " +this.currentColumnHeaders.get(i) +" "; 
                
            }
            document.add(new Paragraph(headers));
            for(int i=0; i<this.tabulateList.size(); i++){
                String list="";
                for(int j=0; j<this.tabulateList.get(i).size(); j++){
                    list+= this.tabulateList.get(i).get(j);
                    list+=" ";
                }
                document.add(new Paragraph(list));
            }
            document.close();
            
         
        } catch (DocumentException ex) {
            Logger.getLogger(TabulateInfoBean.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(TabulateInfoBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    public boolean isAlumniSurvey() {
        return alumniSurvey;
    }

    public void setAlumniSurvey(boolean alumniSurvey) {
        this.alumniSurvey = alumniSurvey;
    }

    public boolean isEmployerSurvey() {
        return employerSurvey;
    }

    public void setEmployerSurvey(boolean employerSurvey) {
        this.employerSurvey = employerSurvey;
    }
}
